package com.zmn.plat.business.impl.price;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.plat.business.interfaces.channel.ChannelCategBService;
import com.zmn.plat.business.interfaces.channel.ChannelServProductBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.business.interfaces.pilot.ChannelPriceBService;
import com.zmn.plat.business.interfaces.price.CommonBService;
import com.zmn.plat.business.interfaces.price.MeterFlowBService;
import com.zmn.plat.business.interfaces.product.ServProductBService;
import com.zmn.plat.common.constant.OnePriceConsts;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.dictionary.BaseBrandRatioTypeEnum;
import com.zmn.plat.common.dictionary.PlatErrorCodeDict;
import com.zmn.plat.common.dto.brand.BaseBrandDRO;
import com.zmn.plat.common.dto.price.ItemTo;
import com.zmn.plat.common.dto.price.meter.*;
import com.zmn.plat.common.dto.product.tariff.TariffBackProductDRO;
import com.zmn.plat.common.dto.product.tariff.TariffProductDRO;
import com.zmn.plat.common.dto.product.tariff.category.TariffCategoryDRO;
import com.zmn.plat.common.dto.product.tariff.category.TariffCategoryPageDRO;
import com.zmn.plat.common.dto.product.tariff.servcategory.TariffServCategoryDRO;
import com.zmn.plat.common.dto.servcategory.ServCategoryChildrenDRO;
import com.zmn.plat.common.enums.PilotConfigEnum;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.dto.price.PriceCalDTO;
import com.zmn.plat.model.dto.product.ProductRelationDTO;
import com.zmn.plat.model.entity.brand.BaseBrand;
import com.zmn.plat.model.entity.brand.BaseBrandQuery;
import com.zmn.plat.model.entity.brand.BrandRatio;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.category.BaseCategoryQuery;
import com.zmn.plat.model.entity.category.ServCategAndCategTwoQuery;
import com.zmn.plat.model.entity.channel.brand.ratio.ChannelBrandRatio;
import com.zmn.plat.model.entity.pilot.SupportPilotVO;
import com.zmn.plat.model.entity.product.*;
import com.zmn.plat.model.entity.product.categorybrand.CategoryBrandQuery;
import com.zmn.plat.model.entity.product.tariff.ProductTariffQuery;
import com.zmn.plat.model.entity.product.tariff.item.ProductItemQuery;
import com.zmn.plat.model.entity.servcategory.ServAssCategoryQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.entity.service.group.ServiceGroup;
import com.zmn.plat.model.entity.service.item.ServiceItem;
import com.zmn.plat.model.entity.service.tariff.ServiceTariff;
import com.zmn.plat.model.vo.product.tariff.ProductTariffVO;
import com.zmn.plat.persistence.interfaces.channel.ChannelServiceCategoryDAO;
import com.zmn.plat.persistence.interfaces.servcategory.ServAssCategoryDao;
import com.zmn.plat.services.interfaces.brand.BaseBrandService;
import com.zmn.plat.services.interfaces.brand.BrandRatioService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.brand.ratio.ChannelBrandRatioService;
import com.zmn.plat.services.interfaces.product.ServProductPictureService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import com.zmn.plat.services.interfaces.product.ServTariffProductRelationService;
import com.zmn.plat.services.interfaces.product.categorybrand.CategoryBrandService;
import com.zmn.plat.services.interfaces.product.tariff.ProductTariffService;
import com.zmn.plat.services.interfaces.product.tariff.item.ProductTariffGroupItemService;
import com.zmn.plat.services.interfaces.product.tariff.item.city.price.ProductTariffItemCityPriceService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;
import com.zmn.plat.services.interfaces.service.group.ServiceGroupService;
import com.zmn.plat.services.interfaces.service.item.ServiceItemService;
import com.zmn.plat.services.interfaces.service.tariff.ServiceTariffService;
import com.zmn.plat.utils.bean.BeanCopyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * 描述: 计价器流程实现类（所有接口前提是有计价器试点，接口是按照操作顺序）
 *
 * @author guoqiao
 * @since 2021/9/13 11:13
 */
@Service
@Slf4j
public class MeterFlowBServiceImpl implements MeterFlowBService {

    @Resource
    CommonBService commonBService;
    @Resource
    MeterFlowBService meterFlowBService;
    @Resource
    ProductTariffGroupItemService productTariffGroupItemService;
    @Resource
    ProductTariffItemCityPriceService productTariffItemCityPriceService;
    @Resource
    ServCategoryService servCategoryService;
    @Resource
    BaseCategoryService baseCategoryService;
    @Resource
    ServProductService servProductService;
    @Resource
    BaseBrandService baseBrandService;
    @Resource
    ServTariffProductRelationService tariffProductRelationService;
    @Resource
    ChannelBrandRatioService channelBrandRatioService;
    @Resource
    BrandRatioService brandRatioService;
    @Resource
    ServProductPictureService servProductPictureService;
    @Resource
    CategoryBrandService categoryBrandService;
    @Resource
    ChannelServiceCategoryBService channelServiceCategoryBService;
    @Resource
    ChannelPriceBService channelPriceBService;
    @Resource
    ChannelServProductBService channelServProductBService;
    @Resource
    ServProductBService servProductBService;
    @Resource
    ServiceTariffService serviceTariffService;
    @Resource
    ServiceGroupService serviceGroupService;
    @Resource
    ChannelCategBService channelCategBService;
    @Resource
    ServAssCategoryDao servAssCategoryDao;
    @Resource
    ProductTariffService productTariffService;

    private static final String ON_ORDER_TARIFFID = "0";

    /**
     * 描述: 1.获取有计价器产品的服务品类
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listServAndCategByChannelIdAndCity:channel:'+#p0+':cityId:'+#p1", unless = "#result == null")
    public List<ServCategoryChildrenDRO> listServAndCategByChannelIdAndCity(Integer channelId, Integer cityId) {

        // 查询有效的服务分类
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listServCategoryAll())
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 查询支持计价器的产品品类
        List<ServCategAndCategTwoQuery> collect1 = Optional.ofNullable(meterFlowBService.listServProductForTariff(channelId, cityId, ProductConsts.BIZ_TYPE_C, null, null))
                .orElse(Collections.emptyList())
                .stream()
                .map(e -> new ServCategAndCategTwoQuery(e.getServCategId(), e.getCategOneId(), e.getCategId()))
                .distinct()
                .collect(Collectors.toList());


        // 按服务分类分组
        Map<Integer, List<ServCategAndCategTwoQuery>> serviceCategoryMap = collect1.stream().collect(groupingBy(ServCategAndCategTwoQuery::getServCategId));
        List<ServCategoryChildrenDRO> ret = serviceCategoryMap.values().stream().map(serviceCategory -> {
            // 按一级分类分组
            Map<Integer, List<ServCategAndCategTwoQuery>> categoryOneMap = serviceCategory.stream().collect(groupingBy(ServCategAndCategTwoQuery::getCategOneId));
            List<ServCategoryChildrenDRO> categoryOneList = categoryOneMap.values().stream().map(categoryOne -> {
                // 二级分类
                List<ServCategoryChildrenDRO> categList = categoryOne.stream()
                        .map(p -> {
                            BaseCategory baseCategory = categoryMap.get(p.getCategTwoId()).get(0);
                            return new ServCategoryChildrenDRO(baseCategory.getCategId(), baseCategory.getTariffName(), baseCategory.getSort(), baseCategory.getIcon(), baseCategory.getSimpleSpell(), null);
                        })
                        .collect(Collectors.toList());
                // 一级分类KvDTO
                BaseCategory baseCategory = categoryMap.get(categoryOne.get(0).getCategOneId()).get(0);
                return new ServCategoryChildrenDRO(baseCategory.getCategId(), baseCategory.getTariffName(), baseCategory.getSort(), baseCategory.getIcon(), baseCategory.getSimpleSpell(), categList);
            }).collect(Collectors.toList());
            // 服务分类
            ServCategory servCategory = servMap.get(serviceCategory.get(0).getServCategId()).get(0);
            return new ServCategoryChildrenDRO(servCategory.getCategId(), servCategory.getTariffName(), servCategory.getSort(), servCategory.getShowHomePageIcon(), servCategory.getShowSimpleSpell(), categoryOneList);

        }).collect(Collectors.toList());

        return ret;
    }

    /**
     * 描述: 2.获取有计价器产品的二级分类
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listTwoCategByChannelIdAndCity:channel:'+#p0+':cityId:'+#p1", unless = "#result == null")
    public TariffCategoryPageDRO listTwoCategByChannelIdAndCity(Integer channelId, Integer cityId) {

        // 查询有效的服务分类
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listServCategoryAll())
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 查询支持计价器的产品分类
        List<TariffCategoryDRO> collect1 = Optional.ofNullable(meterFlowBService.listServProductForTariff(channelId, cityId, ProductConsts.BIZ_TYPE_C, null, null))
                .orElse(Collections.emptyList())
                .stream()
                .map(p -> {
                    ServCategory servCategory = servMap.get(p.getServCategId()).get(0);
                    BaseCategory baseCategory = categoryMap.get(p.getCategId()).get(0);
                    TariffCategoryDRO tariffCategory = new TariffCategoryDRO();
                    BeanCopyUtils.copyProperties(baseCategory, tariffCategory);
                    tariffCategory.setServCategId(servCategory.getCategId());
                    return tariffCategory;
                })
                .distinct()
                .collect(Collectors.toList());

        TariffCategoryPageDRO dro = new TariffCategoryPageDRO(collect1.size(), collect1);
        return dro;
    }

    /**
     * 描述: 3.根据关键字搜索产品二级分类
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listFtCategByQuery:MeterFtCategQuery:'+#p0", unless = "#result == null")
    public List<TariffCategoryDRO> listFtCategByQuery(MeterFtCategQuery query) {

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setName(query.getTariffName());
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 查询支持计价器的产品分类
        List<TariffCategoryDRO> dro = Optional.ofNullable(meterFlowBService.listServProductForTariff(query.getChannelId(), query.getCityId(), query.getBizType(), null, query.getTariffName()))
                .orElse(Collections.emptyList())
                .stream()
                .map(p -> {
                    BaseCategory baseCategory = categoryMap.get(p.getCategId()).get(0);
                    TariffCategoryDRO tariffCategory = new TariffCategoryDRO();
                    BeanCopyUtils.copyProperties(baseCategory, tariffCategory);
                    return tariffCategory;
                })
                .distinct()
                .collect(Collectors.toList());

        return dro;
    }

    /**
     * 描述: 4.根据前台产品二级分类查询服务分类
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listServByQuery:MeterServQuery:'+#p0", unless = "#result == null")
    public List<TariffServCategoryDRO> listServByQuery(MeterServQuery query) {

        // 查询有效的服务分类
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listServCategoryAll())
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询支持计价器的服务
        List<TariffServCategoryDRO> dros = Optional.ofNullable(meterFlowBService.listServProductForTariff(query.getChannelId(), query.getCityId(), query.getBizType(), query.getCategId(), null))
                .orElse(Collections.emptyList())
                .stream()
                .map(p -> {
                    ServCategory categServ = servMap.get(p.getServCategId()).get(0);
                    TariffServCategoryDRO dro = new TariffServCategoryDRO();
                    dro.setShowServCategId(categServ.getCategId());
                    dro.setShowServCategName(categServ.getShowName());
                    dro.setShowTariffName(categServ.getTariffName());
                    return dro;
                })
                .distinct()
                .collect(Collectors.toList());

        return dros;
    }

    /**
     * 描述: 5.根据前台产品服务分类、二级分类查询计价器产品
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listTariffProductByQuery:MeterFtProductQuery:'+#p0", unless = "#result == null")
    public List<TariffProductDRO> listTariffProductByQuery(MeterFtProductQuery query) {

        // 查询计价器产品
        ServProductQuery query2 = new ServProductQuery();
        query2.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        query2.setServCategId(query.getServCategId());
        query2.setCategId(query.getCategId());
        query2.setStatus(GlobalConsts.YES);
        List<ServProduct> productList = servProductService.listByQuery(query2);
        if (CollectionUtils.isEmpty(productList)) {
            return Collections.emptyList();
        }
        List<Integer> productIdList = productList.stream().map(e -> e.getProductId()).collect(Collectors.toList());

        // 查询产品关系数据
        RelationQueryDTO dtoQuery = new RelationQueryDTO();
        BeanCopyUtils.copyProperties(query, dtoQuery);
        dtoQuery.setProductIdList(productIdList);
        dtoQuery.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
        log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
        if (CollectionUtils.isEmpty(relationDTOList)) {
            return Collections.emptyList();
        }

        // 有价格表的产品id集合
        List<Integer> productIdDroList = relationDTOList.stream().map(e -> e.getTariffProductId()).collect(Collectors.toList());

        // 查询图片
        Map<Integer, String> picMap = Optional.ofNullable(servProductPictureService.listByProductIds(productIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServProductPicture::getProductId, ServProductPicture::getSmallPicture));

        List<TariffProductDRO> dros = productList
                .stream()
                .filter(e -> productIdDroList.contains(e.getProductId()))
                .map(e -> {
                    TariffProductDRO dro = new TariffProductDRO();
                    BeanCopyUtils.copyProperties(e, dro);
                    dro.setSmallPicture(picMap.get(e.getProductId()));
                    return dro;
                }).collect(Collectors.toList());
        return dros;
    }

    /**
     * 描述: 6.根据前台产品或计价器产品查询品牌
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listBrandByQuery:MeterBrandQuery:'+#p0", unless = "#result == null")
    public List<BaseBrandDRO> listBrandByQuery(MeterBrandQuery query) {

        Integer channelId = query.getChannelId();
        // 查询前台产品
        ServProduct ftProduct = servProductService.findByKeyWithCache(query.getProductId());
        if (Objects.isNull(ftProduct)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_PRODUCT_NO_DATA);
        }

        // 查询前台分类关联了的品牌
        CategoryBrandQuery categoryBrandQuery = new CategoryBrandQuery();
        categoryBrandQuery.setCategId(ftProduct.getCategId());
        categoryBrandQuery.setStatus(GlobalConsts.YES);
        List<Integer> categBrandIdList = Optional.ofNullable(categoryBrandService.listByQuery(categoryBrandQuery))
                .orElse(Collections.emptyList())
                .stream()
                .map(e -> e.getBrandId())
                .collect(Collectors.toList());

        // 查询产品关系数据
        RelationQueryDTO dtoQuery = new RelationQueryDTO();
        BeanCopyUtils.copyProperties(query, dtoQuery);
        dtoQuery.setProductIdList(Arrays.asList(ftProduct.getProductId()));
        dtoQuery.setShowType(ftProduct.getShowType());
        List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
        log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
        if (CollectionUtils.isEmpty(relationDTOList)) {
            return Collections.emptyList();
        }

        Integer avaliableChannelId = channelId;
        try {
            avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            log.error("无可用渠道");
        }

        // 查询渠道配置的品牌系数
        List<ChannelBrandRatio> channelBrandRatios = channelBrandRatioService.listForFlowByBizType(avaliableChannelId, query.getBizType());
        List<BrandRatio> brandRatios = BeanCopyUtils.copyProperties(channelBrandRatios, ChannelBrandRatio.class, BrandRatio.class, BrandRatio::new);
        if (CollectionUtils.isEmpty(brandRatios)) {
            // 查询基础数据的品牌系数
            brandRatios = brandRatioService.listForFlowByBizType(query.getBizType());
        }
        log.info("品牌系数brandRatios：{}", brandRatios);
        if (CollectionUtils.isEmpty(brandRatios)) {
            return Collections.emptyList();
        }

        List<Integer> brandIdList = new ArrayList<>(brandRatios.size());

        Set<String> categOneStrs = new HashSet<>(relationDTOList.size()); // 后台产品一级分类系数str
        Set<String> categTwoStrs = new HashSet<>(relationDTOList.size()); // 后台产品二级分类系数str
        for (ProductRelationDTO relationDTO : relationDTOList) {
            categOneStrs.add(relationDTO.getServCategId() + "-" + relationDTO.getCategOneId());
            categTwoStrs.add(relationDTO.getServCategId() + "-" + relationDTO.getCategOneId() + "-" + relationDTO.getCategId());
        }

        for (BrandRatio brandRatio : brandRatios) {
            Integer brandId = brandRatio.getBrandId();
            Integer ratioType = brandRatio.getRatioType();
            if (brandIdList.contains(brandId) || !categBrandIdList.contains(brandId)) {
                continue;
            }
            if (Objects.equals(BaseBrandRatioTypeEnum.BRANDCATEGONERATIO.getCode(), ratioType)
                    && categOneStrs.contains(brandRatio.getServCategId() + "-" + brandRatio.getCategOneId())) {
                // 后台产品一级分类系数
                brandIdList.add(brandId);
            } else if (Objects.equals(BaseBrandRatioTypeEnum.BRANDCATEGTWORATIO.getCode(), ratioType)
                    && categTwoStrs.contains(brandRatio.getServCategId() + "-" + brandRatio.getCategOneId() + "-" + brandRatio.getCategId())) {
                // 后台产品二级分类系数
                brandIdList.add(brandId);
            }
        }
        log.info("符合条件的品牌id集合brandIdList：{}", brandIdList);
        if (CollectionUtils.isEmpty(brandIdList)) {
            return Collections.emptyList();
        }

        // 查询品牌信息
        BaseBrandQuery brandQuery = new BaseBrandQuery();
        brandQuery.setBrandIdList(brandIdList);
        brandQuery.setStatus(GlobalConsts.YES);
        List<BaseBrand> baseBrands = baseBrandService.listByQuery(brandQuery);
        List<BaseBrandDRO> baseBrandDROS = BeanCopyUtils.copyProperties(baseBrands, BaseBrand.class, BaseBrandDRO.class, BaseBrandDRO::new);
        return baseBrandDROS;
    }

    /**
     * 描述: 7.根据项目类型查询项目
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listItemByQuery:MeterItemQuery:'+#p0", unless = "#result == null")
    public List<ItemTo> listItemByQuery(MeterItemQuery query) {

        // 查询产品关系数据
        RelationQueryDTO dtoQuery = new RelationQueryDTO();
        BeanCopyUtils.copyProperties(query, dtoQuery);
        dtoQuery.setProductIdList(Arrays.asList(query.getProductId()));
        dtoQuery.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
        log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
        if (CollectionUtils.isEmpty(relationDTOList)) {
            return Collections.emptyList();
        }

        List<Integer> itemIds = new ArrayList<>();
        // 查询项目
        List<ItemTo> result = new ArrayList<>();

        for (ProductRelationDTO relationDTO : relationDTOList) {
            ProductItemQuery itemQuery = new ProductItemQuery();
            itemQuery.setProductId(relationDTO.getProductId());
            itemQuery.setTariffId(relationDTO.getTariffId());
            itemQuery.setItemCategId(query.getItemCategId());
            List<ItemTo> itemTos = Optional.ofNullable(productTariffGroupItemService.listItemPriceByQuery(itemQuery))
                    .orElse(Collections.emptyList());
            log.info("服务项目itemTos：{},条件itemQuery：{}", itemTos, itemQuery);

            // 过滤已选的项目（每个后台产品对应的所有项目必须全包含已选择的项目）
            if (!CollectionUtils.isEmpty(query.getItemIds())) {
                List<Integer> collect = itemTos.stream().map(e -> e.getItemId()).collect(Collectors.toList());
                if (!collect.containsAll(query.getItemIds())) {
                    continue;
                }
            }

            for (ItemTo itemTo : itemTos) {
                if (!itemIds.contains(itemTo.getItemId())) {
                    itemIds.add(itemTo.getItemId());
                    result.add(itemTo);
                }
            }
        }
        return result;
    }

    /**
     * 描述: 8.根据计价器产品查询后台二级分类
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listBkCategByQuery:MeterBkCategQuery:'+#p0", unless = "#result == null")
    public List<TariffCategoryDRO> listBkCategByQuery(MeterBkCategQuery query) {

        // 查询产品关系数据
        RelationQueryDTO dtoQuery = new RelationQueryDTO();
        BeanCopyUtils.copyProperties(query, dtoQuery);
        dtoQuery.setProductIdList(Arrays.asList(query.getProductId()));
        dtoQuery.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
        log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
        if (CollectionUtils.isEmpty(relationDTOList)) {
            return Collections.emptyList();
        }

        List<Integer> categIds = new ArrayList<>();
        // 查询项目
        List<TariffCategoryDRO> result = new ArrayList<>();

        for (ProductRelationDTO relationDTO : relationDTOList) {
            ProductItemQuery itemQuery = new ProductItemQuery();
            itemQuery.setProductId(relationDTO.getProductId());
            itemQuery.setTariffId(relationDTO.getTariffId());
            List<ItemTo> itemTos = Optional.ofNullable(productTariffGroupItemService.listItemPriceByQuery(itemQuery))
                    .orElse(Collections.emptyList());
            log.info("服务项目itemTos：{},条件itemQuery：{}", itemTos, itemQuery);

            // 过滤已选的项目（每个后台产品对应的所有项目必须全包含已选择的项目）
            if (!CollectionUtils.isEmpty(query.getItemIds())) {
                List<Integer> collect = itemTos.stream().map(e -> e.getItemId()).collect(Collectors.toList());
                if (!collect.containsAll(query.getItemIds())) {
                    continue;
                }
            }
            Integer categId = relationDTO.getCategId();
            if (!categIds.contains(categId)) {
                categIds.add(categId);
                // 查询二级分类
                BaseCategory category = baseCategoryService.findByKey(categId);
                TariffCategoryDRO dro = new TariffCategoryDRO();
                BeanCopyUtils.copyProperties(category, dro);
                result.add(dro);
            }
        }
        return result;
    }

    /**
     * 描述: 9.根据计价器产品查询后台产品
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listBkProductByQuery:MeterBkProductQuery:'+#p0", unless = "#result == null")
    public List<TariffBackProductDRO> listBkProductByQuery(MeterBkProductQuery query) {

        // 查询产品关系数据
        RelationQueryDTO dtoQuery = new RelationQueryDTO();
        BeanCopyUtils.copyProperties(query, dtoQuery);
        dtoQuery.setProductIdList(Arrays.asList(query.getProductId()));
        dtoQuery.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
        log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);

        // 过滤后台产品二级分类
        relationDTOList = relationDTOList.stream().filter(e -> Objects.equals(query.getCategId(), e.getCategId())).collect(Collectors.toList());
        log.info("过滤后台产品二级分类后的数据relationDTOFilterList：{}", relationDTOList);

        if (CollectionUtils.isEmpty(relationDTOList)) {
            return Collections.emptyList();
        }

        // 查询项目
        List<TariffBackProductDRO> result = new ArrayList<>();

        for (ProductRelationDTO relationDTO : relationDTOList) {

            ProductItemQuery itemQuery = new ProductItemQuery();
            itemQuery.setProductId(relationDTO.getProductId());
            itemQuery.setTariffId(relationDTO.getTariffId());
            List<ItemTo> itemTos = Optional.ofNullable(productTariffGroupItemService.listItemPriceByQuery(itemQuery))
                    .orElse(Collections.emptyList());
            log.info("服务项目itemTos：{},条件itemQuery：{}", itemTos, itemQuery);

            // 过滤已选的项目（每个后台产品对应的所有项目必须全包含已选择的项目）
            if (!CollectionUtils.isEmpty(query.getItemIds())) {
                List<Integer> collect = itemTos.stream().map(e -> e.getItemId()).collect(Collectors.toList());
                if (!collect.containsAll(query.getItemIds())) {
                    continue;
                }
            }
            Integer productId = relationDTO.getProductId();
            // 查询产品
            ServProduct servProduct = servProductService.findByKeyWithCache(productId);
            TariffBackProductDRO dro = new TariffBackProductDRO();
            BeanCopyUtils.copyProperties(servProduct, dro);
            dro.setProductName(servProduct.getName());
            dro.setProductTariffName(servProduct.getTariffName());
            dro.setProductSort(servProduct.getSort());
            result.add(dro);
        }
        return result;
    }

    /**
     * 描述: 10.计价器报价
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listQuoteByQuery:MeterQuoteQuery:'+#p0", unless = "#result == null")
    public List<ItemTo> listQuoteByQuery(MeterQuoteQuery query) {

        List<ItemTo> dros = new ArrayList<>();
        Map<Integer, Integer> itemIdProductIdmap = new HashMap();

        for (ProductItem productItem : query.getProductItemList()) {
            Integer productId = productItem.getProductId();
            Integer tariffId = productItem.getTariffId();
            List<Integer> itemList = productItem.getItemList();
            for (Integer itemid : itemList) {
                itemIdProductIdmap.put(itemid, productId);
            }
            if (NumberUtil.isNullOrZero(tariffId)) {
                // 查询产品关系数据
                RelationQueryDTO dtoQuery = new RelationQueryDTO();
                BeanCopyUtils.copyProperties(query, dtoQuery);
                dtoQuery.setProductIdList(Arrays.asList(productId));
                dtoQuery.setShowType(ProductConsts.ERP_PRODUCT_TYPE);
                List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
                log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
                if (CollectionUtils.isEmpty(relationDTOList)) {
                    continue;
                }
                tariffId = relationDTOList.get(0).getTariffId();
            }

            QuoteQueryDTO dto = new QuoteQueryDTO();
            BeanCopyUtils.copyProperties(query, dto);
            dto.setProductId(productId);
            dto.setTariffId(tariffId);
            dto.setItemIds(itemList);
            dto.setBrandId(productItem.getBrandId());
            dto.setDifficultId(productItem.getDifficultId());
            // 查询项目价格
            dros.addAll(meterFlowBService.listItemToByDto(dto));
        }
        return dros;
    }

    /**
     * 描述: 11.计价器报价（后台产品二级分类或后台产品不清楚）
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listQuoteUnknowByQuery:MeterQuoteUnknowQuery:'+#p0", unless = "#result == null")
    public List<MeterQuoteUnknowDRO> listQuoteUnknowByQuery(MeterQuoteUnknowQuery query) {

        List<Integer> itemList = query.getItemIds();

        // 查询产品关系数据
        RelationQueryDTO dtoQuery = new RelationQueryDTO();
        BeanCopyUtils.copyProperties(query, dtoQuery);
        dtoQuery.setProductIdList(Arrays.asList(query.getProductId()));
        dtoQuery.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
        log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);

        // 过滤后台产品二级分类
        if (NumberUtil.isNotNullOrZero(query.getCategId())) {
            relationDTOList = relationDTOList.stream().filter(e -> Objects.equals(query.getCategId(), e.getCategId())).collect(Collectors.toList());
            log.info("过滤后台产品二级分类后的数据relationDTOFilterList：{}", relationDTOList);
        }
        if (CollectionUtils.isEmpty(relationDTOList)) {
            return Collections.emptyList();
        }

        // 查询品牌
        String brandName = "";
        if (NumberUtil.isNotNullOrZero(query.getBrandId())) {
            BaseBrand brand = baseBrandService.findByKey(query.getBrandId());
            brandName = brand.getName();
        }

        List<MeterQuoteUnknowDRO> dros = new ArrayList<>(relationDTOList.size());
        for (ProductRelationDTO relationDTO : relationDTOList) {
            Integer productId = relationDTO.getProductId();

            QuoteQueryDTO dto = new QuoteQueryDTO();
            BeanCopyUtils.copyProperties(query, dto);
            dto.setProductId(productId);
            dto.setTariffId(relationDTO.getTariffId());
            // 查询项目价格
            List<ItemTo> itemToList = meterFlowBService.listItemToByDto(dto);
            if (CollectionUtils.isEmpty(itemToList)) {
                continue;
            }

            // 查询后台产品
            ServProduct product = servProductService.findByKeyWithCache(productId);
            // 组装数据
            MeterQuoteUnknowDRO dro = new MeterQuoteUnknowDRO();
            dro.setProductId(productId);
            dro.setProductName(product.getName());
            dro.setProductTariffName(product.getTariffName());
            dro.setBrandName(brandName);
            dro.setItemToList(itemToList);
            dros.add(dro);
        }
        return dros;
    }

    /**
     * 描述: 12.根据后台产品id和项目类型查询项目价格
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listItemPriceByItemCategId:MeterItemPriceQuery:'+#p0", unless = "#result == null")
    public List<ItemTo> listItemPriceByItemCategId(MeterItemPriceQuery query) {

        if (NumberUtil.isNullOrZero(query.getItemCategId())) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        Integer productId = query.getProductId();
        Integer tariffId = query.getTariffId();
        if (NumberUtil.isNullOrZero(tariffId)) {
            // 查询产品关系数据
            RelationQueryDTO dtoQuery = new RelationQueryDTO();
            BeanCopyUtils.copyProperties(query, dtoQuery);
            dtoQuery.setProductIdList(Arrays.asList(productId));
            dtoQuery.setShowType(ProductConsts.ERP_PRODUCT_TYPE);
            List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
            log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
            if (CollectionUtils.isEmpty(relationDTOList)) {
                return Collections.emptyList();
            }
            tariffId = relationDTOList.get(0).getTariffId();
        }

        QuoteQueryDTO dto = new QuoteQueryDTO();
        BeanCopyUtils.copyProperties(query, dto);
        dto.setTariffId(tariffId);
        // 查询项目价格
        return meterFlowBService.listItemToByDto(dto);
    }

    /**
     * 描述: 13.根据后台产品id和收费标准查询项目价格
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listItemPriceByPriceStandard:MeterItemPriceQuery:'+#p0", unless = "#result == null")
    public List<ItemTo> listItemPriceByPriceStandard(MeterItemPriceQuery query) {

        Integer priceStandard = query.getPriceStandard();
        if (NumberUtil.isNullOrZero(priceStandard)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_TARIFF_PRODUCT_PARAM_ERROR);
        }
        Integer productId = query.getProductId();
        Integer tariffId = query.getTariffId();
        if (NumberUtil.isNullOrZero(tariffId)) {
            // 查询产品关系数据
            RelationQueryDTO dtoQuery = new RelationQueryDTO();
            BeanCopyUtils.copyProperties(query, dtoQuery);
            dtoQuery.setProductIdList(Arrays.asList(productId));
            dtoQuery.setShowType(ProductConsts.ERP_PRODUCT_TYPE);
            List<ProductRelationDTO> relationDTOList = meterFlowBService.listProductRelationDTO(dtoQuery);
            log.info("满足条件的产品关系数据relationDTOList：{}", relationDTOList);
            if (CollectionUtils.isEmpty(relationDTOList)) {
                return Collections.emptyList();
            }
            tariffId = relationDTOList.get(0).getTariffId();
        }

        QuoteQueryDTO dto = new QuoteQueryDTO();
        BeanCopyUtils.copyProperties(query, dto);
        dto.setTariffId(tariffId);
        // 查询项目价格
        List<ItemTo> itemToList = meterFlowBService.listItemToByDto(dto).stream()
                .filter(e -> {
                    // 过滤是否一口价
                    boolean flag = Objects.equals(e.getPriceStandard(), priceStandard);
                    if (flag && Objects.equals(GlobalConsts.NO, priceStandard)) {
                        // 非一口价时返回默认服务项
                        flag = Objects.equals(e.getGeneral(), GlobalConsts.YES);
                    }
                    return flag;
                }).collect(Collectors.toList());

        return itemToList;
    }


    /********************************* 以下是内部调用的接口 *********************************/

    /**
     * 描述: 根据渠道id和城市查询支持计价器的产品（公共内部方法，供1.2.3.4接口调用）
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listServProductForTariff:channel:'+#p0+':city:'+#p1+':bizType:'+#p2+':categId:'+#p3+':categName:'+#p4", unless = "#result == null")
    public List<ServProduct> listServProductForTariff(Integer channelId, Integer cityId, Integer bizType, Integer categId, String categName) {
        try {
            Integer avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
            channelId = avaliableChannelId;
        } catch (PlatException e) {
            return null;
        }
        // 查询有效的服务分类
        Map<Integer, List<ServCategory>> servMap = Optional.ofNullable(servCategoryService.listServCategoryAll())
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(ServCategory::getCategId));

        // 查询有效的前台产品分类
        BaseCategoryQuery categoryQuery = new BaseCategoryQuery();
        categoryQuery.setCategId(categId);
        categoryQuery.setName(categName);
        categoryQuery.setStatus(GlobalConsts.YES);
        categoryQuery.setShowType(ProductConsts.EC_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> categoryMap = Optional.ofNullable(
                baseCategoryService.listByQuery(categoryQuery))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.groupingBy(BaseCategory::getCategId));

        // 根据渠道id和城市id查询计价器试点分类
        SupportPilotVO supportPilotVO = channelPriceBService.listPilotCategs(channelId, cityId, OnePriceConsts.TARIFF, null, null);
        if (Objects.isNull(supportPilotVO) || CollectionUtils.isEmpty(supportPilotVO.getServCategIdList())) {
            log.error("没有开通试点的产品");
            return null;
        }
        List<String> politCollect = supportPilotVO.getServCategIdList()
                .stream()
                .map(m -> m.getServCategId() + "-" + m.getCategOneId() + "-" + m.getCategTwoId())
                .collect(Collectors.toList());

        // 渠道开通前台的服务分类
        List<String> channelServCollect = Optional.ofNullable(channelCategBService.listServCategAndCategTwoQueryByChannelIdAndShowType(channelId, cityId, ProductConsts.EC_PRODUCT_TYPE))
                .orElse(Collections.emptyList())
                .stream()
                .map(i -> i.getServCategId() + "-" + i.getCategOneId() + "-" + i.getCategTwoId())
                .collect(Collectors.toList());

        // 服务与产品的关联关系
        List<String> servAssCategoryCollect = Optional.ofNullable(servAssCategoryDao.listByQuery(new ServAssCategoryQuery()))
                .orElse(Collections.emptyList())
                .stream()
                .map(i -> i.getServCategId() + "-" + i.getCategOneId() + "-" + i.getCategId())
                .collect(Collectors.toList());

        // 渠道禁用的后台产品
        ChannelProductQuery channelProductQuery = ChannelProductQuery.builder()
                .channelId(channelId)
                .showType(ProductConsts.ERP_PRODUCT_TYPE)
                .status(GlobalConsts.NO)
                .build();
        List<Integer> disableProductIdS = Optional.ofNullable(channelServProductBService.listChannelServProductByQuery(channelProductQuery))
                .orElse(Collections.emptyList())
                .stream()
                .map(m -> m.getProductId())
                .collect(Collectors.toList());

        // 与后台产品有关联关系的计价器产品
        List<Integer> tariffProductIds = Optional.ofNullable(tariffProductRelationService.listByQuery(new ServTariffProductRelationQuery()))
                .orElse(Collections.emptyList())
                .stream()
                .filter(m -> !disableProductIdS.contains(m.getProductId()))
                .map(m -> m.getTariffProductId())
                .collect(Collectors.toList());

        Integer channelIdFin = channelId;

        // 查询计价器产品对应的品类
        ServProductQuery query = new ServProductQuery();
        query.setShowType(ProductConsts.ET_PRODUCT_TYPE);
        query.setCategId(categId);
        query.setStatus(GlobalConsts.YES);
        List<ServProduct> productList = Optional.ofNullable(servProductService.listByQuery(query))
                .orElse(Collections.emptyList())
                .stream()
                // 过滤服务分类和产品分类
                .filter(e -> servMap.containsKey(e.getServCategId()) && categoryMap.containsKey(e.getCategId()))
                // 过滤计价器试点分类
                .filter(e -> politCollect.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                // 过滤渠道开通的分类
                .filter(e -> channelServCollect.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                // 过滤服务分类和产品分类的关联关系
                .filter(e -> servAssCategoryCollect.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                // 过滤被渠道禁用的后台产品对对应的计价器产品
                .filter(e -> tariffProductIds.contains(e.getProductId()))
                // 过滤是否有可用价格表
                .filter(e -> commonBService.checkTariff(channelIdFin, e.getProductId(), ProductConsts.ET_PRODUCT_TYPE, bizType))
                .collect(Collectors.toList());
        return productList;
    }

    /**
     * 描述: 查询符合条件的产品关系数据（公共内部方法，供5.6.7.8.9.10.11.12接口调用）
     * 1.查询产品关系数据；2.查询价格表；3.筛选出价格表优先的数据；4.过滤满足品牌的数据
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listProductRelationDTO:RelationQueryDTO:'+#p0", unless = "#result == null")
    public List<ProductRelationDTO> listProductRelationDTO(RelationQueryDTO dto) {
        Integer channelId = dto.getChannelId();
        Integer bizType = dto.getBizType();
        Integer brandId = dto.getBrandId();
        Integer cityId = dto.getCityId();
        Integer tariffId = dto.getTariffId();
        Integer avaliableChannelId = channelId;
        try {
            avaliableChannelId = channelServiceCategoryBService.getAvailableCategoryChannelId(channelId);
        } catch (PlatException e) {
            log.error("无可用渠道");
        }

        // 查询前台、后台、计价器产品关系
        List<ProductRelationDTO> relationDTOList = Optional.ofNullable
                (servProductBService.listProductRalationByIdListAndShowType(dto.getProductIdList(), dto.getShowType()))
                .orElse(Collections.emptyList())
                .stream()
                .filter(e -> Objects.equals(e.getTariffStatus(), GlobalConsts.YES) && Objects.equals(e.getTariffProductStatus(), GlobalConsts.YES))
                .collect(Collectors.toList());

        if (NumberUtil.isNullOrZero(tariffId)) {
            if (Objects.equals(ON_ORDER_TARIFFID, String.valueOf(tariffId))) {
                // 在途订单,只考虑计价器价格表（兼容线上环境，后续可删除）
                commonBService.getTariffByOnOrder(relationDTOList, channelId, cityId, bizType);
                log.info("在途订单，兼容处理后的产品关系价格表relationDTOList：{}", relationDTOList);
            } else {
                // 查询价格表
                commonBService.getTariffByPilot(relationDTOList, channelId, cityId, bizType);
                log.info("计算后的产品关系价格表relationDTOList：{}", relationDTOList);

                // 筛选出价格表优先的数据
                commonBService.filterTariff(relationDTOList, ProductConsts.ET_PRODUCT_TYPE, true);
                log.info("筛选出价格表优先的数据relationDTOList：{}", relationDTOList);
            }
        } else {
            // 带订单（有价格表）
            relationDTOList.forEach(e -> e.setTariffId(tariffId));
        }

        // 通过品牌过滤后台产品
        if (NumberUtil.isNullOrZero(brandId) || CollectionUtils.isEmpty(relationDTOList)) {
            return relationDTOList;
        }
        // 查询渠道配置的品牌系数
        List<ChannelBrandRatio> channelBrandRatios = channelBrandRatioService.listForFlowByBizType(avaliableChannelId, bizType);
        List<BrandRatio> brandRatios = BeanCopyUtils.copyProperties(channelBrandRatios, ChannelBrandRatio.class, BrandRatio.class, BrandRatio::new);
        if (CollectionUtils.isEmpty(brandRatios)) {
            // 查询基础数据的品牌系数
            brandRatios = brandRatioService.listForFlowByBizType(bizType);
        }
        log.info("品牌系数brandRatios：{}", brandRatios);
        brandRatios = brandRatios.stream().filter(e -> Objects.equals(e.getBrandId(), brandId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(brandRatios)) {
            log.error("根据品牌筛选数据，该品牌在品牌系数中未配置数据，brandId={}", brandId);
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_PRODUCT_BRAND_NO_DATA);
        }

        List<String> categOneStrs = new ArrayList<>(brandRatios.size()); // 后台产品一级分类系数str
        List<String> categTwoStrs = new ArrayList<>(brandRatios.size()); // 后台产品二级分类系数str
        for (BrandRatio brandRatio : brandRatios) {
            if (Objects.equals(BaseBrandRatioTypeEnum.BRANDCATEGONERATIO.getCode(), brandRatio.getRatioType())) {
                categOneStrs.add(brandRatio.getServCategId() + "-" + brandRatio.getCategOneId());
            } else if (Objects.equals(BaseBrandRatioTypeEnum.BRANDCATEGTWORATIO.getCode(), brandRatio.getRatioType())) {
                categTwoStrs.add(brandRatio.getServCategId() + "-" + brandRatio.getCategOneId() + "-" + brandRatio.getCategId());
            }
        }
        // 过滤数据
        relationDTOList = relationDTOList.stream()
                .filter(e -> categOneStrs.contains(e.getServCategId() + "-" + e.getCategOneId()) ||
                        categTwoStrs.contains(e.getServCategId() + "-" + e.getCategOneId() + "-" + e.getCategId()))
                .collect(Collectors.toList());
        return relationDTOList;
    }

    /**
     * 描述: 服务项目计算价格（公共内部方法，供10.11.12接口调用）
     */
    @Override
    @Cacheable(cacheNames = "redis5m", key = "'price:listItemToByDto:QuoteQueryDTO:'+#p0", unless = "#result == null")
    public List<ItemTo> listItemToByDto(QuoteQueryDTO dto) {
        // 查询价格表
        ServiceTariff tariff = serviceTariffService.findByKeyWithCache(dto.getTariffId());
        if (Objects.isNull(tariff)) {
            throw new PlatException(PlatErrorCodeDict.ERROR_CODE_SERVICE_TARIFF_NULL);
        }
        // 查询后台产品
        ServProduct product = servProductService.findByKeyWithCache(dto.getProductId());

        // 查询item集合
        List<ItemTo> itemToList = new ArrayList<>();
        ProductItemQuery itemQuery = new ProductItemQuery();
        itemQuery.setProductId(dto.getProductId());
        itemQuery.setTariffId(dto.getTariffId());
        itemQuery.setItemIds(dto.getItemIds());
        itemQuery.setItemCategId(dto.getItemCategId());
        if (Objects.equals(tariff.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_CITY)) {
            // 城市定价
            itemQuery.setCityId(dto.getCityId());
            itemToList = productTariffItemCityPriceService.listItemPriceByQuery(itemQuery);
        } else {
            // 系数定价
            itemToList = productTariffGroupItemService.listItemPriceByQuery(itemQuery);
        }
        log.info("项目itemToList:{}", itemToList);
        if (CollectionUtils.isEmpty(itemToList)) {
            return Collections.emptyList();
        }

        // 查询后台产品与价格表关系
        ProductTariffQuery productTariffQuery = new ProductTariffQuery();
        productTariffQuery.setProductId(dto.getProductId());
        productTariffQuery.setTariffId(dto.getTariffId());
        productTariffQuery.setStatus(GlobalConsts.YES);
        ProductTariffVO productTariff = productTariffService.listByQueryWithCache(productTariffQuery)
                .stream()
                .findFirst()
                .orElse(new ProductTariffVO());

        // 分组Map
        List<Integer> groupIdList = itemToList.stream().map(m -> m.getGroupId()).distinct().collect(Collectors.toList());
        Map<Integer, String> groupMap = Optional.ofNullable(serviceGroupService.listByGroupIds(groupIdList))
                .orElse(Collections.emptyList())
                .stream()
                .collect(Collectors.toMap(ServiceGroup::getGroupId, ServiceGroup::getGroupName));

        PriceCalDTO calDTO = new PriceCalDTO(dto.getChannelId(), dto.getCityId(), dto.getBrandId(), dto.getBizType(), dto.getDifficultId());

        for (ItemTo itemTo : itemToList) {
            // 设置定价方式(计算价格前需设置定价方式)
            itemTo.setTariffName(tariff.getTariffName());
            itemTo.setTariffType(tariff.getTariffType());
            itemTo.setPriceType(tariff.getPriceType());
            itemTo.setGroupName(groupMap.get(itemTo.getGroupId()));

            // 计算单价
            commonBService.calPriceDetail(itemTo, calDTO);
            log.info("项目itemTo计算价格后数据:{}", itemTo);
            itemTo.setProductName(product.getName());
            itemTo.setProductSort(product.getSort());
            itemTo.setDesc(productTariff.getDesc());
            itemTo.setSpecialDesc(productTariff.getSpecialDesc());
        }
        return itemToList;
    }

}

